package org.zhaolei.component;

import com.amazonaws.HttpMethod;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.IOUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
//import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class MinIOFileStoreEngine implements StoreEngine{

    @Resource
    private AmazonS3Client amazonS3Client;

    @Override
    public boolean bucketExists(String bucketName) {
        if (bucketName == null || bucketName.isEmpty()) {
            log.warn("bucketName不能为空");
            return false;
        }
        return amazonS3Client.doesBucketExistV2(bucketName);
    }

    @Override
    public boolean removeBucket(String bucketName) {
        if (bucketName == null || bucketName.isEmpty()) {
            log.warn("bucketName不能为空");
            return false;
        }
        try {
            if (!bucketExists(bucketName)) {
                log.warn("bucket不存在");
                return false;
            }

            List<S3ObjectSummary> objects = listObjects(bucketName);
            if (objects != null && !objects.isEmpty()) {
                log.warn("Bucket name: {} is not empty, cannot delete", bucketName);
                return false;
            }

            amazonS3Client.deleteBucket(bucketName);
            boolean exists = bucketExists(bucketName);
            if (exists) {
                log.warn("Failed to delete bucket: {}", bucketName);
                return false;
            }
            log.info("Bucket name: {} deleted successfully", bucketName);
            return true;
        } catch (Exception e) {
            log.error("删除bucket异常:{}",e);
            return false;
        }
    }

    @Override
    public void createBucket(String bucketName) {
        if (bucketName == null || bucketName.isEmpty()) {
            log.warn("Bucket name is null or empty");
            return;
        }
        try {
            if (bucketExists(bucketName)) {
                log.info("Bucket name: {} already exists", bucketName);
                return;
            }

            amazonS3Client.createBucket(bucketName);
            log.info("Bucket name: {} created successfully", bucketName);
        } catch (Exception e) {
            log.error("创建bucket异常:{}", bucketName, e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<Bucket> getAllBucket() {
        try {
            return amazonS3Client.listBuckets();
        } catch (Exception e) {
            log.error("获取bucket异常:{}", e);
//            throw new RuntimeException(e);
            return List.of();
        }
    }

    @Override
    public List<S3ObjectSummary> listObjects(String bucketName) {
        if (bucketName == null || bucketName.isEmpty()) {
            log.warn("Bucket name is null or empty");
            return List.of();
        }
        if (!bucketExists(bucketName)) {
            return List.of();
        }
        try {
            return amazonS3Client.listObjects(bucketName).getObjectSummaries();
        } catch (Exception e) {
            log.error("Error listing objects in bucket: {}", bucketName, e);
            return List.of();
        }
    }

    /**
     * 判断对象是否存在
     * @param bucketName
     * @param objectKey
     * @return
     */
    @Override
    public boolean doesObjectExist(String bucketName, String objectKey) {
        //判断入参
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty()) {
            log.warn("Bucket name or objectKey is null or empty");
            return false;
        }
        //逻辑上判断bucket是否存在
        if (!bucketExists(bucketName)) {
            return false;
        }
        return amazonS3Client.doesObjectExist(bucketName, objectKey);
    }

    /**
     * 上传文件到指定bucket
     * @param bucketName 桶名称
     * @param objectKey 上传后对象的名称
     * @param localFileName 本地文件的路径
     * @return
     */
    @Override
    public boolean upload(String bucketName, String objectKey, String localFileName) {
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty() || localFileName == null || localFileName.isEmpty()) {
            log.warn("Invalid parameters for upload");
            return false;
        }
        if (!bucketExists(bucketName)) {
            log.warn("Bucket does not exist: {}", bucketName);
            return false;
        }
        try {
            //如果这里直接用一个字符串上传文件，会发生什么？报什么错误？
            amazonS3Client.putObject(bucketName, objectKey, new File(localFileName));
            log.info("File uploaded to bucket: {}, key: {}", bucketName, objectKey);
            return true;
        } catch (Exception e) {
            log.error("Error uploading file to bucket: {}, key: {}", bucketName, objectKey, e);
            return false;
        }
    }

    /**
     * 上传MultipartFile文件到指定bucket
     * @param bucketName 桶名称
     * @param objectKey 上传后对象的名称
     * @param file 文件对象
     * @return
     */
    @Override
    public boolean upload(String bucketName, String objectKey, MultipartFile file) {
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty() || file == null) {
            log.warn("Invalid parameters for multipart upload");
            return false;
        }
        if (!bucketExists(bucketName)) {
            log.warn("Bucket does not exist: {}", bucketName);
            return false;
        }
        try {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            metadata.setContentLength(file.getSize());
            amazonS3Client.putObject(bucketName, objectKey, file.getInputStream(), metadata);
            log.info("Multipart file uploaded to bucket: {}, key: {}", bucketName, objectKey);
            return true;
        } catch (Exception e) {
            log.error("Error uploading multipart file to bucket: {}, key: {}", bucketName, objectKey, e);
            return false;
        }
    }

    /**
     * 删除指定bucket下的指定对象
     * @param bucketName 桶名称
     * @param objectKey 要删除的对象的名称
     * @return
     */
    @Override
    public boolean delete(String bucketName, String objectKey) {
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty()) {
            log.warn("Invalid parameters for delete");
            return false;
        }
        if (!bucketExists(bucketName)) {
            return false;
        }
        try {
            amazonS3Client.deleteObject(bucketName, objectKey);
            boolean exists = doesObjectExist(bucketName, objectKey);
            if (exists) {
                log.error("Failed to delete object: {}/{}", bucketName, objectKey);
                return false;
            }
            log.info("Object deleted from bucket: {}, key: {}", bucketName, objectKey);
            return true;
        } catch(Exception e) {
            log.error("Error deleting object: {}/{}", bucketName, objectKey, e);
            return false;
        }
    }

    /**
     * 获取对象下载的URL,预签名下载链接
     * @param bucketName 桶名称
     * @param objectKey 对象的名称
     * @param timeout URL的有效时长
     * @param unit URL有效时长的时间单位
     * @return
     */
    @Override
    public String getDownloadUrl(String bucketName, String objectKey, long timeout, TimeUnit unit) {
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty()) {
            log.warn("Invalid parameters for generating download URL");
            return null;
        }
        if (!bucketExists(bucketName)) {
            return null;
        }
        try {
            Date expiration = new Date(System.currentTimeMillis() + unit.toMillis(timeout));
            String url = amazonS3Client.generatePresignedUrl(bucketName, objectKey, expiration).toString();
            log.info("Generated download URL for object: {}/{}", bucketName, objectKey);
            return url;
        } catch(Exception e) {
            log.error("Error generating download URL for object: {}/{}", bucketName, objectKey, e);
            return null;
        }
    }

    /**
     * 将对象内容写入HTTPServletResponse对象，用于浏览器下载
     * 能够理解这个接口的大意，后面重点要测试一下效果，知道了效果就知道以后运用在什么地方了！！
     * @param bucketName 桶名称
     * @param objectKey 对象的名称
     * @param response HTTP响应对象，用于输出下载的对象
     */
    @Override
    public void download2Response(String bucketName, String objectKey, HttpServletResponse response) {
        if (bucketName == null || bucketName.isEmpty() || objectKey == null || objectKey.isEmpty()) {
            log.warn("Invalid parameters for download");
            return;
        }
        if (!bucketExists(bucketName)) {
            log.warn("Bucket does not exist: {}", bucketName);
            return;
        }
        try(S3Object s3Object = amazonS3Client.getObject(bucketName, objectKey)) {
            String fileName = extractFileName(objectKey);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("utf-8");

            IOUtils.copy(s3Object.getObjectContent(), response.getOutputStream());
            log.info("File downloaded from bucket: {}, key: {}", bucketName, objectKey);
        } catch (IOException e) {
            log.error("Error downloading file from bucket: {}, key: {}", bucketName, objectKey, e);
        }
    }

    /**
     * 提取文件名，防止路径问题，从最后斜杠开始到字符串最后是文件名
     * @param objectKey 对象名称
     * @return
     */
    @Override
    public String extractFileName(String objectKey) {
        int lastSlashIndex = objectKey.lastIndexOf("/");
        if (lastSlashIndex >= 0 && lastSlashIndex < objectKey.length() - 1) {
            return objectKey.substring(lastSlashIndex + 1);
        }
        return objectKey;
    }

    @Override
    public PartListing listMultipart(String bucketName, String objectKey, String uploadId) {
        try {
            ListPartsRequest request = new ListPartsRequest(bucketName, objectKey, uploadId);
            return amazonS3Client.listParts(request);
        } catch (Exception e) {
            log.error("errorMsg={}", e);
            return null;
        }
    }

    @Override
    public InitiateMultipartUploadResult initMultipartUploadTask(String bucketName, String objectKey, ObjectMetadata metadata) {
        try {
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectKey, metadata);
            return amazonS3Client.initiateMultipartUpload(request);
        } catch (Exception e) {
            log.error("errorMsg={}", e);
            return null;
        }
    }

    @Override
    public URL genePreSignedUrl(String bucketName, String objectKey, HttpMethod httpMethod, Date expiration, Map<String, Object> params) {
        try {
            GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey, httpMethod)
                    .withExpiration(expiration);
            //遍历params作为参数加到genePreSignedUrlReq里面，比如 添加上传ID和分片编号作为请求参数
            //genePreSignedUrlReq.addRequestParameter("uploadId", uploadId);
            //genePreSignedUrlReq.addRequestParameter("partNumber", String.valueOf(i));
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                generatePresignedUrlRequest.addRequestParameter(entry.getKey(), entry.getValue().toString());
            }
            //生成并获取签名URL
            return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest);
        } catch (Exception e) {
            log.error("errorMsg={}", e);
            return null;
        }

    }

    @Override
    public CompleteMultipartUploadResult mergeChunks(String bucketName, String objectKey, String uploadId, List<PartETag> partETags) {
        CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partETags);
        return amazonS3Client.completeMultipartUpload(request);
    }
}
